package com.taotao.springboot2.common.mybatis.plus.update.force;


import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 *
 * spring环境下例子：
 * <pre>{@code
 *
 * DataSource dataSource;// 获取数据源
 * MybatisPlusForceUpdater  mybatisPlusForceUpdater = new MybatisPlusForceUpdater(){
 *      @Override
 *      protected Connection currentConnection() throws SQLException {
 *           return  DataSourceUtils.getConnection(dataSource);
 *      }
 * };
 * }</pre>
 *
 * 原生mybatis例子,就要看数据连接是怎么取的,自己实现currentConnection()方法。
 *
 * @author youbeiwuhuan
 * @version 1.0.0
 * @date 2023/7/13 17:55
 */

public abstract class MybatisPlusForceUpdater {

    protected Log log = LogFactory.getLog(getClass());


    public <T> int forceUpdateById(T entity) {
        if (null == entity) {
            throw new IllegalArgumentException();
        }

        if (!(entity instanceof UpdateWrapper)) {
            throw new IllegalStateException("please wrapper entity with UpdateEntity.of() before call setter!!");
        }


        TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
        UpdateWrapper updateWrapper = (UpdateWrapper) entity;
        Map<String, Object> updates = updateWrapper.getUpdates();
        List<Object> params = new ArrayList<>(updates.size() + 1);


        // 拼sql
        StringBuilder sql = new StringBuilder("UPDATE ");
        sql.append(tableInfo.getTableName()).append(" SET ");
        for (String propName : updates.keySet()) {
            if (Objects.equals(propName, tableInfo.getKeyProperty())) {
                continue;
            }

            TableFieldInfo tableField = TableInfoUtil.getTableFieldInfoByProperty(propName, tableInfo);
            sql.append(tableField.getColumn()).append("= ?,");
        }

        sql.replace(sql.length() - 1, sql.length(), "");

        sql.append(" WHERE ").append(tableInfo.getKeyColumn()).append(" = ?");


        Connection conn = null;
        PreparedStatement st = null;
        try {
            conn = currentConnection();
            st = conn.prepareStatement(sql.toString());
            int i = 1;
            for (Map.Entry<String, Object> e : updates.entrySet()) {
                if (Objects.equals(e.getKey(), tableInfo.getKeyProperty())) {
                    continue;
                }

                st.setObject(i, e.getValue());
                params.add(e.getValue());
                i++;
            }

            Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty());
            st.setObject(i, idVal);
            params.add(idVal);

            log.debug("==>  Preparing: " + sql);
            log.debug("==>  Parameters: " + JSON.toJSONString(params));
//            log.debug("==>  Parameters: " + params.toString());


            int effectRows = st.executeUpdate();
            log.debug("<==    Updates: " + effectRows);
            return effectRows;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            if (null != st) {
                try {
                    st.close();
                } catch (SQLException e1) {

                }
            }

            // Connection 由外层事务释放
        }

    }


    /**
     * 获取当前事务使用的数据库连接
     *
     * @return
     * @throws SQLException
     */
    protected abstract Connection currentConnection() throws SQLException;


}
